1//////////////////////////////////////////////////////////////////////////
  2// LibFile: cubetruss.scad
  3//   Parts for making modular open-frame cross-braced trusses and connectors.
  4// Includes:
  5//   include <BOSL2/std.scad>
  6//   include <BOSL2/cubetruss.scad>
  7// FileGroup: Parts
  8// FileSummary: Modular open-framed trusses and joiners.
  9//////////////////////////////////////////////////////////////////////////
 10
 11$cubetruss_size = 30;
 12$cubetruss_strut_size = 4;
 13$cubetruss_bracing = true;
 14$cubetruss_clip_thickness = 1.6;
 15
 16
 17// Section: Cube Trusses
 18
 19// Module: cubetruss()
 20// Synopsis: Creates a multi-cube straight cubetruss shape.
 21// SynTags: Geom
 22// Topics: Trusses, CubeTruss, FDM Optimized, Parts
 23// See Also: cubetruss_segment(), cubetruss_support(), cubetruss(), cubetruss_corner()
 24// Usage:
 25//   cubetruss(extents, [clips=], [bracing=], [size=], [strut=], [clipthick=], ...) [ATTACHMENTS];
 26// Description:
 27//   Creates a cubetruss truss, assembled out of one or more cubical segments.
 28// Arguments:
 29//   extents = The number of cubes in length to make the truss.  If given as a [X,Y,Z] vector, specifies the number of cubes in each dimension.
 30//   clips = List of vectors pointing towards the sides to add clips to.
 31//   bracing = If true, adds internal cross-braces.  Default: `$cubetruss_bracing` (usually true)
 32//   size = The length of each side of the cubetruss cubes.  Default: `$cubetruss_size` (usually 30)
 33//   strut = The width of the struts on the cubetruss cubes.  Default: `$cubetruss_strut_size` (usually 3)
 34//   clipthick = The thickness of the clips.  Default: `$cubetruss_clip_thickness` (usually 1.6)
 35//   ---
 36//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
 37//   spin = Rotate this many degrees around the Z axis.  See [spin](attachments.scad#subsection-spin).  Default: `0`
 38//   orient = Vector to rotate top towards.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
 39// Examples:
 40//   cubetruss(extents=3);
 41//   cubetruss(extents=3, clips=FRONT);
 42//   cubetruss(extents=3, clips=[FRONT,BACK]);
 43//   cubetruss(extents=[2,3]);
 44//   cubetruss(extents=[1,4,2]);
 45//   cubetruss(extents=[1,4,2], bracing=false);
 46module cubetruss(extents=6, clips=[], bracing, size, strut, clipthick, anchor=CENTER, spin=0, orient=UP) {
 47    clips = is_vector(clips)? [clips] : clips;
 48    size = is_undef(size)? $cubetruss_size : size;
 49    strut = is_undef(strut)? $cubetruss_strut_size : strut;
 50    bracing = is_undef(bracing)? $cubetruss_bracing : bracing;
 51    clipthick = is_undef(clipthick)? $cubetruss_clip_thickness : clipthick;
 52    extents = is_vector(extents)? point3d(extents,fill=1) : [1,extents,1];
 53    w = extents[0];
 54    l = extents[1];
 55    h = extents[2];
 56    s = [cubetruss_dist(w,1), cubetruss_dist(l,1), cubetruss_dist(h,1)];
 57    attachable(anchor,spin,orient, size=s) {
 58        union() {
 59            for (zrow = [0:h-1]) {
 60                up((zrow-(h-1)/2)*(size-strut)) {
 61                    for (xcol = [0:w-1]) {
 62                        right((xcol-(w-1)/2)*(size-strut)) {
 63                            for (ycol = [0:l-1]) {
 64                                back((ycol-(l-1)/2)*(size-strut)) {
 65                                    cubetruss_segment(size=size, strut=strut, bracing=bracing);
 66                                }
 67                            }
 68                        }
 69                    }
 70                }
 71            }
 72            if (clipthick > 0) {
 73                for (vec = clips) {
 74                    exts = v_abs(rot(from=FWD, to=vec, p=extents));
 75                    rot(from=FWD,to=vec) {
 76                        for (zrow = [0:1:exts.z-1]) {
 77                            up((zrow-(exts.z-1)/2)*(size-strut)) {
 78                                fwd((exts.y*(size-strut)+strut)/2) {
 79                                    cubetruss_clip(size=size, strut=strut, extents=exts.x, clipthick=clipthick);
 80                                }
 81                            }
 82                        }
 83                    }
 84                }
 85            }
 86        }
 87        children();
 88    }
 89}
 90
 91
 92// Module: cubetruss_corner()
 93// Synopsis: Creates a multi-cube corner cubetruss shape.
 94// SynTags: Geom
 95// Topics: Trusses, CubeTruss, FDM Optimized, Parts
 96// See Also: cubetruss_segment(), cubetruss_support(), cubetruss(), cubetruss_corner()
 97// Usage:
 98//   cubetruss_corner(h, extents, [bracing=], [size=], [strut=], [clipthick=]);
 99// Description:
100//   Creates a corner cubetruss with extents jutting out in one or more directions.
101// Arguments:
102//   h = The number of cubes high to make the base and horizontal extents.
103//   extents = The number of cubes to extend beyond the corner.  If given as a vector of cube counts, gives the number of cubes to extend right, back, left, front, and up in order.  If the vector is shorter than length 5 the extra cube counts are taken to be zero.  
104//   bracing = If true, adds internal cross-braces.  Default: `$cubetruss_bracing` (usually true)
105//   size = The length of each side of the cubetruss cubes.  Default: `$cubetruss_size` (usually 30)
106//   strut = The width of the struts on the cubetruss cubes.  Default: `$cubetruss_strut_size` (usually 3)
107//   clipthick = The thickness of the clips.  Default: `$cubetruss_clip_thickness` (usually 1.6)
108//   ---
109//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
110//   spin = Rotate this many degrees around the Z axis.  See [spin](attachments.scad#subsection-spin).  Default: `0`
111//   orient = Vector to rotate top towards.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
112// Examples:
113//   cubetruss_corner(extents=2);
114//   cubetruss_corner(extents=2, h=2);
115//   cubetruss_corner(extents=[3,3,0,0,2]);
116//   cubetruss_corner(extents=[3,0,3,0,2]);
117//   cubetruss_corner(extents=[3,3,3,3,2]);
118module cubetruss_corner(h=1, extents=[1,1,0,0,1], bracing, size, strut, clipthick, anchor=CENTER, spin=0, orient=UP) {
119    size = is_undef(size)? $cubetruss_size : size;
120    strut = is_undef(strut)? $cubetruss_strut_size : strut;
121    bracing = is_undef(bracing)? $cubetruss_bracing : bracing;
122    clipthick = is_undef(clipthick)? $cubetruss_clip_thickness : clipthick;
123    exts = is_vector(extents)? list_pad(extents,5,fill=0) : [extents, extents, 0, 0, extents];
124    dummy = assert(len(exts)==5, "Input extents must be a scalar or vector with length 5 or less.");
125    s = [cubetruss_dist(exts[0]+1+exts[2],1), cubetruss_dist(exts[1]+1+exts[3],1), cubetruss_dist(h+exts[4],1)];
126    offset = [cubetruss_dist(exts[0]-exts[2],0), cubetruss_dist(exts[1]-exts[3],0), cubetruss_dist(h+exts[4]-1,0)]/2;
127    attachable(anchor,spin,orient, size=s, offset=offset) {
128        union() {
129            for (zcol = [0:h-1]) {
130                up((size-strut)*zcol) {
131                    cubetruss_segment(size=size, strut=strut, bracing=bracing);
132                }
133            }
134            for (dir = [0:3]) {
135                if (exts[dir] != undef && exts[dir] > 0) {
136                    zrot(dir*90) {
137                        for (zcol = [0:h-1]) {
138                            up((size-strut+0.01)*zcol) {
139                                for (i = [1:exts[dir]]) {
140                                    right((size-strut+0.01)*i) cubetruss_segment(size=size, strut=strut, bracing=bracing);
141                                }
142                                if (clipthick > 0) {
143                                    right(exts[dir]*(size-strut)+size/2) {
144                                        zrot(90) cubetruss_clip(size=size, strut=strut, clipthick=clipthick);
145                                    }
146                                }
147                            }
148                        }
149                    }
150                }
151            }
152            if (exts[4] != undef && exts[4] > 0) {
153                for (i = [1:exts[4]]) {
154                    up((size-strut+0.01)*(i+h-1)) cubetruss_segment(size=size, strut=strut, bracing=bracing);
155                }
156                if (clipthick > 0) {
157                    up((exts[4]+h-1)*(size-strut)+size/2) {
158                        xrot(-90) cubetruss_clip(size=size, strut=strut, clipthick=clipthick);
159                    }
160                }
161            }
162        }
163        children();
164    }
165}
166
167
168// Module: cubetruss_support()
169// Synopsis: Creates a cubetruss support structure shape.
170// SynTags: Geom
171// Topics: Trusses, CubeTruss, FDM Optimized, Parts
172// See Also: cubetruss_segment(), cubetruss_support(), cubetruss(), cubetruss_corner()
173// Usage:
174//   cubetruss_support([size=], [strut=], [extents=]) [ATTACHMENTS];
175// Description:
176//   Creates a single cubetruss support.
177// Arguments:
178//   size = The length of each side of the cubetruss cubes.  Default: `$cubetruss_size` (usually 30)
179//   strut = The width of the struts on the cubetruss cubes.  Default: `$cubetruss_strut_size` (usually 3)
180//   extents = If given as an integer, specifies the number of vertical segments for the support.  If given as a list of 3 integers, specifies the number of segments in the X, Y, and Z directions.  Default: 1.
181//   ---
182//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
183//   spin = Rotate this many degrees around the Z axis.  See [spin](attachments.scad#subsection-spin).  Default: `0`
184//   orient = Vector to rotate top towards.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
185// Example(VPT=[0,0,0],VPD=150):
186//   cubetruss_support();
187// Example(VPT=[0,0,0],VPD=200):
188//   cubetruss_support(extents=2);
189// Example(VPT=[0,0,0],VPD=250):
190//   cubetruss_support(extents=3);
191// Example(VPT=[0,0,0],VPD=350):
192//   cubetruss_support(extents=[2,2,3]);
193// Example(VPT=[0,0,0],VPD=150):
194//   cubetruss_support(strut=4);
195// Example(VPT=[0,0,0],VPD=260):
196//   cubetruss_support(extents=2) show_anchors();
197module cubetruss_support(size, strut, extents=1, anchor=CENTER, spin=0, orient=UP) {
198    extents = is_num(extents)? [1,1,extents] : extents;
199    size = is_undef(size)? $cubetruss_size : size;
200    strut = is_undef(strut)? $cubetruss_strut_size : strut;
201    check =
202      assert(is_int(extents.x) && extents.x > 0)
203      assert(is_int(extents.y) && extents.y > 0)
204      assert(is_int(extents.z) && extents.z > 0);
205    w = (size-strut) * extents.x + strut;
206    l = (size-strut) * extents.y + strut;
207    h = (size-strut) * extents.z + strut;
208    attachable(anchor,spin,orient, size=[w,l,h], size2=[l,0], shift=[0,l/2], axis=DOWN) {
209        xcopies(size-strut, n=extents.x) {
210            difference() {
211                half_of(BACK/extents.y + UP/extents.z, s=size*(max(extents)+1))
212                    cube([size,l,h], center=true);
213                half_of(BACK/extents.y + UP/extents.z, cp=strut, s=size*(max(extents)+1)) {
214                    ycopies(size-strut, n=extents.y) {
215                        zcopies(size-strut, n=extents.z) {
216                            cyl(h=size+1, d=size-2*strut, circum=true, realign=true, orient=RIGHT, $fn=8);
217                            cyl(h=size+1, d=size-2*strut, circum=true, realign=true, $fn=8);
218                            cube(size-2*strut, center=true);
219                        }
220                    }
221                }
222                zcopies(size-strut, n=extents.z) {
223                    cyl(h=extents.y*size+1, d=size-2*strut, circum=true, realign=true, orient=BACK, $fn=8);
224                }
225            }
226        }
227        children();
228    }
229}
230
231
232
233// Section: Cubetruss Support
234
235// Module: cubetruss_foot()
236// Synopsis: Creates a foot that can connect two cubetrusses.
237// SynTags: Geom
238// Topics: Trusses, CubeTruss, FDM Optimized, Parts
239// See Also: cubetruss_segment(), cubetruss_support(), cubetruss(), cubetruss_corner()
240// Usage:
241//   cubetruss_foot(w, [size=], [strut=], [clipthick=]) [ATTACHMENTS];
242// Description:
243//   Creates a foot that can be clipped onto the bottom of a truss for support.
244// Arguments:
245//   w = The number of cube segments to span between the clips.  Default: 1
246//   size = The length of each side of the cubetruss cubes.  Default: `$cubetruss_size` (usually 30)
247//   strut = The width of the struts on the cubetruss cubes.  Default: `$cubetruss_strut_size` (usually 3)
248//   clipthick = The thickness of the clips.  Default: `$cubetruss_clip_thickness` (usually 1.6)
249//   ---
250//   $slop = make fit looser to allow for printer overextrusion
251//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
252//   spin = Rotate this many degrees around the Z axis.  See [spin](attachments.scad#subsection-spin).  Default: `0`
253//   orient = Vector to rotate top towards.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
254// Examples:
255//   cubetruss_foot(w=1);
256//   cubetruss_foot(w=3);
257module cubetruss_foot(w=1, size, strut, clipthick, anchor=CENTER, spin=0, orient=UP) {
258    size = is_undef(size)? $cubetruss_size : size;
259    strut = is_undef(strut)? $cubetruss_strut_size : strut;
260    clipthick = is_undef(clipthick)? $cubetruss_clip_thickness : clipthick;
261    clipsize = 0.5;
262    wall_h = strut+clipthick*1.5;
263    cyld = (size-2*strut)/cos(180/8);
264    s = [w*(size-strut)+strut+2*clipthick, size-2*strut, strut+clipthick];
265    attachable(anchor,spin,orient, size=s, offset=[0,0,(strut-clipthick)/2]) {
266        down(clipthick) {
267            // Base
268            up(clipthick/2) {
269                cuboid([w*(size-strut)+strut+2*clipthick, size-2*strut, clipthick], chamfer=strut, edges="Z");
270            }
271
272            // Walls
273            xcopies(w*(size-strut)+strut+clipthick) {
274                up(clipthick-0.01) {
275                    prismoid([clipthick, (size-4*strut)], [clipthick, size/3.5], h=wall_h, anchor=BOT);
276                }
277            }
278
279            // Horiz Wall Clips
280            up(clipthick+strut+get_slop()*2) {
281                xcopies(w*(size-strut)+strut) {
282                    prismoid([clipsize*2, size/3.5], [0.1, size/3.5], h=clipsize*3, anchor=BOT);
283                }
284            }
285
286            // Middle plugs
287            for (xcol = [0:w-1]) {
288                right((xcol-(w-1)/2)*(size-strut)) {
289                    difference() {
290                        // Start with octagon to fit sides.
291                        up(clipthick-0.01) {
292                            zrot(180/8) cylinder(h=strut, d1=cyld-4*get_slop(), d2=cyld-4*get_slop()-1, center=false, $fn=8);
293                        }
294
295                        // Bevel to fit.
296                        up(clipthick+strut) {
297                            ycopies(size-2*strut-4*get_slop()) {
298                                chamfer_edge_mask(l=size-strut, chamfer=strut*2/3, orient=RIGHT);
299                            }
300                        }
301
302                        // Cut out X for possible top mount.
303                        zrot_copies([-45, 45]) {
304                            cube([size*3, strut/sqrt(2)+2*get_slop(), size*3], center=true);
305                        }
306                    }
307                }
308            }
309        }
310        children();
311    }
312}
313
314
315// Module: cubetruss_joiner()
316// Synopsis: Creates a joiner that can connect two cubetrusses end-to-end.
317// SynTags: Geom
318// Topics: Trusses, CubeTruss, FDM Optimized, Parts
319// See Also: cubetruss_segment(), cubetruss_support(), cubetruss(), cubetruss_corner()
320// Usage:
321//   cubetruss_joiner([w=], [vert=], [size=], [strut=], [clipthick=]) [ATTACHMENTS];
322// Description:
323//   Creates a part to join two cubetruss trusses end-to-end.
324// Arguments:
325//   w = The number of cube segments to span between the clips.  Default: 1
326//   vert = If true, add vertical risers to clip to the ends of the cubetruss trusses.  Default: true
327//   size = The length of each side of the cubetruss cubes.  Default: `$cubetruss_size` (usually 30)
328//   strut = The width of the struts on the cubetruss cubes.  Default: `$cubetruss_strut_size` (usually 3)
329//   clipthick = The thickness of the clips.  Default: `$cubetruss_clip_thickness` (usually 1.6)
330//   ---
331//   $slop = Make fit looser by this amount to allow for printer overextrusion
332//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
333//   spin = Rotate this many degrees around the Z axis.  See [spin](attachments.scad#subsection-spin).  Default: `0`
334//   orient = Vector to rotate top towards.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
335// Examples:
336//   cubetruss_joiner(w=1, vert=false);
337//   cubetruss_joiner(w=1, vert=true);
338//   cubetruss_joiner(w=2, vert=true, anchor=BOT);
339module cubetruss_joiner(w=1, vert=true, size, strut, clipthick, anchor=CENTER, spin=0, orient=UP) {
340    size = is_undef(size)? $cubetruss_size : size;
341    strut = is_undef(strut)? $cubetruss_strut_size : strut;
342    clipthick = is_undef(clipthick)? $cubetruss_clip_thickness : clipthick;
343    clipsize = 0.5;
344    s = [cubetruss_dist(w,1)+2*clipthick, cubetruss_dist(2,0)-0.1, strut+clipthick];
345    attachable(anchor,spin,orient, size=s, offset=[0,0,-(clipthick-strut)/2]) {
346        down(clipthick) {
347            // Base
348            cube([w*(size-strut)+strut+2*clipthick, size, clipthick], anchor=BOT);
349
350            xcopies(w*(size-strut)+strut+clipthick) {
351                cube([clipthick, size, clipthick+strut*3/4], anchor=BOT);
352            }
353
354            // Use feet
355            ycopies(size) {
356                cubetruss_foot(w=w, size=size, strut=strut, clipthick=clipthick, anchor=BOT);
357            }
358
359            if (vert) {
360                // Vert Walls
361                xcopies(w*(size-strut)+strut+clipthick) {
362                    up(clipthick-0.01) {
363                        prismoid([clipthick, size], [clipthick, 2*strut+2*clipthick], h=size*0.6, anchor=BOT);
364                    }
365                }
366
367                // Vert Wall Clips
368                up(size/2) {
369                    xflip_copy(offset=(w*(size-strut)+strut+0.02)/2) {
370                        yflip_copy(offset=strut+get_slop()/2) {
371                            yrot(-90) {
372                                back_half() {
373                                    prismoid([size/3.5, clipthick*2], [size/3.5-4*2*clipsize, 0.1], h=2*clipsize, anchor=BOT);
374                                }
375                            }
376                        }
377                    }
378                }
379            }
380        }
381        children();
382    }
383}
384
385
386// Module: cubetruss_uclip()
387// Synopsis: Creates a joiner that can connect two cubetrusses end-to-end.
388// SynTags: Geom
389// Topics: Trusses, CubeTruss, FDM Optimized, Parts
390// See Also: cubetruss_segment(), cubetruss_support(), cubetruss(), cubetruss_corner()
391// Usage:
392//   cubetruss_uclip(dual, [size=], [strut=], [clipthick=]) [ATTACHMENTS];
393// Description:
394//   Creates a small clip that can snap around one or two adjacent struts.
395// Arguments:
396//   dual = If true, create a clip to clip around two adjacent struts.  If false, just fit around one strut.  Default: true
397//   size = The length of each side of the cubetruss cubes.  Default: `$cubetruss_size` (usually 30)
398//   strut = The width of the struts on the cubetruss cubes.  Default: `$cubetruss_strut_size` (usually 3)
399//   clipthick = The thickness of the clips.  Default: `$cubetruss_clip_thickness` (usually 1.6)
400//   ---
401//   $slop = Make fit looser by this amount
402//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
403//   spin = Rotate this many degrees around the Z axis.  See [spin](attachments.scad#subsection-spin).  Default: `0`
404//   orient = Vector to rotate top towards.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
405// Examples:
406//   cubetruss_uclip(dual=false);
407//   cubetruss_uclip(dual=true);
408module cubetruss_uclip(dual=true, size, strut, clipthick, anchor=CENTER, spin=0, orient=UP) {
409    size = is_undef(size)? $cubetruss_size : size;
410    strut = is_undef(strut)? $cubetruss_strut_size : strut;
411    clipthick = is_undef(clipthick)? $cubetruss_clip_thickness : clipthick;
412    clipsize = 0.5;
413    s = [(dual?2:1)*strut+2*clipthick+get_slop(), strut+2*clipthick, size/3.5];
414    attachable(anchor,spin,orient, size=s) {
415        union() {
416            difference() {
417                cube(s, center=true);
418                back(clipthick) cube([(dual?2:1)*strut+get_slop(), strut+2*clipthick, size+1], center=true);
419            }
420            back((strut+get_slop())/2) {
421                xflip_copy(offset=(dual?1:0.5)*strut+get_slop()/2) {
422                    yrot(-90) {
423                        back_half() {
424                            prismoid([size/3.5, clipthick*1.87], [size/3.5, 0.1], h=clipsize, anchor=BOT);
425                        }
426                    }
427                }
428            }
429        }
430        children();
431    }
432}
433
434
435
436// Section: Cubetruss Primitives
437
438// Module: cubetruss_segment()
439// Synopsis: Creates a single cubetruss cube.
440// SynTags: Geom
441// Topics: Trusses, CubeTruss, FDM Optimized, Parts
442// See Also: cubetruss_segment(), cubetruss_support(), cubetruss(), cubetruss_corner()
443// Usage:
444//   cubetruss_segment([size=], [strut=], [bracing=]);
445// Description:
446//   Creates a single cubetruss cube segment.
447// Arguments:
448//   size = The length of each side of the cubetruss cubes.  Default: `$cubetruss_size` (usually 30)
449//   strut = The width of the struts on the cubetruss cubes.  Default: `$cubetruss_strut_size` (usually 3)
450//   bracing = If true, adds internal cross-braces.  Default: `$cubetruss_bracing` (usually true)
451//   ---
452//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
453//   spin = Rotate this many degrees around the Z axis.  See [spin](attachments.scad#subsection-spin).  Default: `0`
454//   orient = Vector to rotate top towards.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
455// Examples:
456//   cubetruss_segment(bracing=false);
457//   cubetruss_segment(bracing=true);
458//   cubetruss_segment(strut=4);
459//   cubetruss_segment(size=40);
460module cubetruss_segment(size, strut, bracing, anchor=CENTER, spin=0, orient=UP) {
461    size = is_undef(size)? $cubetruss_size : size;
462    strut = is_undef(strut)? $cubetruss_strut_size : strut;
463    bracing = is_undef(bracing)? $cubetruss_bracing : bracing;
464    h = size;
465    crossthick = strut/sqrt(2);
466    voffset = 0.333;
467    attachable(anchor,spin,orient, size=[size,size,size]) {
468        render(convexity=10)
469        union() {
470            difference() {
471                // Start with a cube.
472                cube([size, size, h], center=true);
473
474                cube([size-strut*2, size-strut*2, h-strut*2+1], center=true);
475
476                // Hollow out octogons in X and Y axes.
477                zrot_copies([0,90]) {
478                    xrot(90) zrot(180/8) cylinder(h=max(h,size)+1, d=(min(h,size)-2*strut)/cos(180/8), center=true, $fn=8);
479                }
480
481                // Hollow out octogon vertically.
482                zrot(180/8) cylinder(h=max(h,size)+1, d=(min(h,size)-2*strut)/cos(180/8), center=true, $fn=8);
483            }
484
485            // Interior cross-supports
486            if (bracing) {
487                for (i = [-1,1]) {
488                    zrot(i*45) {
489                        difference() {
490                            cube([crossthick, (size-strut)*sqrt(2), h], center=true);
491                            up(i*voffset) {
492                                yscale(1.3) {
493                                    yrot(90) {
494                                        zrot(180/6) {
495                                            cylinder(h=crossthick+1, d=(min(h,size)-2*strut)/cos(180/6)-2*voffset, center=true, $fn=6);
496                                        }
497                                    }
498                                }
499                            }
500                        }
501                    }
502                }
503            }
504        }
505        children();
506    }
507}
508
509
510// Module: cubetruss_clip()
511// Synopsis: Creates a clip for the end of a cubetruss to snap-lock it to another cubetruss.
512// SynTags: Geom
513// Topics: Trusses, CubeTruss, FDM Optimized, Parts
514// See Also: cubetruss_segment(), cubetruss_support(), cubetruss(), cubetruss_corner()
515// Usage:
516//   cubetruss_clip(extents, [size=], [strut=], [clipthick=]) [ATTACHMENTS];
517// Description:
518//   Creates a pair of clips to add onto the end of a truss.
519// Arguments:
520//   extents = How many cubes to separate the clips by.
521//   size = The length of each side of the cubetruss cubes.  Default: `$cubetruss_size` (usually 30)
522//   strut = The width of the struts on the cubetruss cubes.  Default: `$cubetruss_strut_size` (usually 3)
523//   clipthick = The thickness of the clip.  Default: `$cubetruss_clip_thickness` (usually 1.6)
524//   ---
525//   $slop = allowance for printer overextrusion
526//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
527//   spin = Rotate this many degrees around the Z axis.  See [spin](attachments.scad#subsection-spin).  Default: `0`
528//   orient = Vector to rotate top towards.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
529// Examples:
530//   cubetruss_clip(extents=2);
531//   cubetruss_clip(extents=1);
532//   cubetruss_clip(clipthick=2.5);
533module cubetruss_clip(extents=1, size, strut, clipthick, anchor=CENTER, spin=0, orient=UP) {
534    size = is_undef(size)? $cubetruss_size : size;
535    strut = is_undef(strut)? $cubetruss_strut_size : strut;
536    clipthick = is_undef(clipthick)? $cubetruss_clip_thickness : clipthick;
537    cliplen = strut * 2.6;
538    clipheight = min(size+strut, size/3+2*strut*2.6);
539    clipsize = 0.5;
540    s = [extents*(size-strut)+strut+2*clipthick, strut*2, clipheight-2*strut];
541    attachable(anchor,spin,orient, size=s) {
542        xflip_copy(offset=(extents*(size-strut)+strut)/2) {
543            difference() {
544                union() {
545                    difference() {
546                        right(clipthick/2-0.01) {
547                            back(strut) {
548                                difference() {
549                                    xrot(90) prismoid([clipthick, clipheight], [clipthick, clipheight-cliplen*2], h=cliplen);
550                                    right(clipthick/2) chamfer_edge_mask(l=clipheight+0.1, chamfer=clipthick);
551                                }
552                            }
553                        }
554                        fwd(strut*3/2) {
555                            cube([get_slop(), strut*3, size], center=true);
556                        }
557                    }
558                    right(get_slop()/2+0.01) {
559                        fwd(strut*1.25+get_slop()) {
560                            yrot(-90) prismoid([clipheight-cliplen*2, strut/2], [clipheight-cliplen*2-2*clipsize, strut/2], h=clipsize+0.01);
561                        }
562                    }
563                }
564                fwd(strut*1.6) {
565                    left(clipsize) {
566                        yscale(1.5) chamfer_edge_mask(l=size+1, chamfer=clipsize+clipthick/3);
567                    }
568                }
569                zcopies(clipheight-strut) cube([clipthick*3, cliplen*2, strut], center=true);
570                zcopies(clipheight-2*strut) right(clipthick) chamfer_edge_mask(l=cliplen*2, chamfer=clipthick, orient=BACK);
571            }
572        }
573        children();
574    }
575}
576
577
578// Function: cubetruss_dist()
579// Synopsis: Returns the length of a cubetruss truss.
580// Topics: Trusses, CubeTruss, FDM Optimized, Parts
581// See Also: cubetruss_segment(), cubetruss_support(), cubetruss(), cubetruss_corner()
582// Usage:
583//   length = cubetruss_dist(cubes, [gaps], [size=], [strut=]);
584// Description:
585//   Function to calculate the length of a cubetruss truss.
586// Arguments:
587//   cubes = The number of cubes along the truss's length.
588//   gaps = The number of extra strut widths to add in, corresponding to each time a truss butts up against another.
589//   size = The length of each side of the cubetruss cubes.  Default: `$cubetruss_size` (usually 30)
590//   strut = The width of the struts on the cubetruss cubes.  Default: `$cubetruss_strut_size` (usually 3)
591function cubetruss_dist(cubes=0, gaps=0, size, strut) =
592    let(
593        size = is_undef(size)? $cubetruss_size : size,
594        strut = is_undef(strut)? $cubetruss_strut_size : strut
595    ) cubes*(size-strut)+gaps*strut;
596
597
598
599// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap